/*
********************************************************************************
* 文件: input.c
* 模块: input, 字符输入的具体函数。
* 代词: in_
* 版本: 
* 历史:
********************************************************************************
*/


#include <stdlib.h>
#include "character.h"

#include "input.h"


/*
********************************************************************************
* 功能:
*    分配一个 input_context 结构，以供后面的函数所用。
*    
* 输入:
*    输入代码的文件名.
*    文件内的语言码值
*
* 输出:
*    返回 0，表示失败。
*    否则返回的数据块可被后面的函数所用。
*
* 修改:
*    返回 tetra 类型, 不再返回指针.
*
********************************************************************************
*/
tetra  in_init_context( tetra * fname, tetra code )
{
    tetra  i;
    input_context * pict;
    
    pict = malloc( sizeof(input_context) );         // 分配数据结构。
    
    if( pict == NULL )
    {
        return 0;
    }
    
    if( fname != 0 )                                // 打开文件。
    {
        for( i=0; i<255; i++ )
        {
            if( fname[i] == 0 )
            {
                break;
            }
            pict->fname[i] = fname[i];
        }
        pict->fname[i] = 0;
        
        // 功能修改。
        // 打开真正的文件。
        pict->fp = stdin;
    }
    else
    {
        pict->fname[0] = 0;
        pict->fp = fopen( "temp.s", "rb" );
        if( pict->fp == NULL )
        {
            return 0;
        }
    }
    
    // 功能填加。
    // 根据参数 code 的值来选择文件解码函数，甚至是压缩文件等。
    pict->readfunc = read_ascii;                    // 文件编码。
    
    pict->line = 1;                                 // 当前行数。 
    pict->position = 0;                             // 行中的位置。
    pict->flag = 0;                            // 模态。
    pict->value = 0x20;                             // 当前字符。

    return (tetra)pict;                                    // 返回。
}




/*
********************************************************************************
* 功能:
*    使用上面定义的这个 input_context 上下文结构，读取文件中的下一个字符。
*
* 输入:
*    input_context * , 所使用的上下文结构。
*
* 输出:
*    input_context * , 此结构中的 value 成员指出读取的字符值。
*    应该定义两个特殊字符，一个是文件结束 0xFFFFFFFF，一个是错误的字符值( 表明该字符不属于指定的
*    编码之中 )
*
********************************************************************************
*/

tetra  in_next_char( tetra  ptetra )
{
    tetra      temp;
    input_context *  pict;

    pict = (input_context *)ptetra;
    
    if( pict->flag == 0 )                      // 根据 flag;
    {
        temp = pict->readfunc( pict->fp );         // 读一个字符。
        
        if( temp == 0xFFFFFFFF )                   // 文件结束。
        {
            if( pict->value == 0x0A )           // 上一个字符是换行。
            {
                // vv vv vv vv
                pict->flag = 4;
                pict->value = 0xFFFFFFFF;
            }
            else                                    // 上一个字符不是换行，在这里填加一个换行符。
            {
                // vv vv vv vv
                pict->flag = 2;
                pict->value = 0x0A;
            }
        }
        else if( temp == 0x0A )                    // 行结束符。
        {
            pict->line ++;
            pict->position = 0;
            pict->flag = 0;
            pict->value = temp;
        }
        else                                        // 平常字符。
        {
            pict->position ++;
            pict->flag = 0;
            pict->value = temp;
        }
    }
    else if( pict->flag == 1 )                 // 上次应用过 unput 功能，这次不需要读。
    {
        if( pict->value == 0x0A )                    // 行结束符。
        {
            pict->line ++;
            pict->position = 0;
            pict->flag = 0;
        }
        else                                        // 平常字符。
        {
            pict->position ++;
            pict->flag = 0;
        }

        // pict->value = pict->value;
    }
    else if( pict->flag == 2 )                 // 
    {
        pict->flag = 4;
        pict->value = 0xFFFFFFFF;
    }
    else if( pict->flag == 3 )
    {
        pict->flag = 2;
        pict->value = 0x0A;
    }
    else
    {
        pict->value = 0xFFFFFFFF;
    }
    
    // 功能填加。
    // 计算 pict->value 的 type1, type2 的值。
    
    return pict->value;
}




/*
********************************************************************************
* 功能:
*    在输入文件中，读取下一个字符，但这个字符不能是 space 或 tab 。
*    在调用此函数之后，in_context * 结构中的 value 就是那个不是 space 或 tab 的字符。
*    
* 输入:
*    input_context * , 所使用的上下文结构。
*
* 输出:
*    input_context * , 此结构中的 value 成员指出读取的字符值。
*    应该定义两个特殊字符，一个是文件结束 0xFFFFFFFF，一个是错误的字符值( 表明该字符不属于指定的
*    编码之中 )
*
********************************************************************************
*/

tetra  in_next_nospace( tetra  ptetra )
{
    tetra  temp;
    input_context *  pict;

    pict = (input_context *)ptetra;
    
    if( pict->flag == 1 && pict->value != 0x20 && pict->value != 0x09 )
    {
        if( pict->value == 0x0A )                    // 行结束符。
        {
            pict->line ++;
            pict->position = 0;
            pict->flag = 0;
        }
        else                                        // 平常字符。
        {
            pict->position ++;
            pict->flag = 0;
        }

    }
    else if( pict->flag == 2 )
    {
        pict->flag = 4;
        pict->value = 0xFFFFFFFF;
    }
    else if( pict->flag == 3 )
    {
        pict->flag = 2;
        pict->value = 0x0A;
    }
    else if( pict->flag >= 4 )
    {
        pict->flag = 4;
        pict->value = 0xFFFFFFFF;
    }
    else
    {
        for(;;)
        {
            temp = pict->readfunc( pict->fp );
            if( temp == 0xFFFFFFFF )
            {
                pict->flag = 2;
                pict->value = 0x0A;
                break;
            }
            else if( temp == 0x0A )
            {
                pict->line ++;
                pict->position = 0;
                
                pict->flag = 0;
                pict->value = 0x0A;
                break;
            }
            else if( temp != 0x20 || temp != 0x09 )
            {
                pict->flag = 0;
                pict->value = temp;
                pict->position ++;
                break;
            }
            else
            {
                pict->flag = 0;
                pict->value = temp;
                pict->position ++;
                continue;
            }
        }
    }
    
    return pict->value;
}




/*
********************************************************************************
* 功能:
*    使用上面定义的这个 input_context 上下文结构，读取文件中的下一个字符。
*
* 输入:
*    input_context * , 所使用的上下文结构。
*
* 输出:
*    input_context * , 此结构中的 value 成员指出读取的字符值。
*    应该定义两个特殊字符，一个是文件结束 0xFFFFFFFF，一个是错误的字符值( 表明该字符不属于指定的
*    编码之中 )
*
********************************************************************************
*/

void  in_unput_char( tetra  ptetra )
{
    input_context *  pict;

    pict = (input_context *)ptetra;
    
    if( pict->flag == 0 )
    {
        pict->flag = 1;
        if( pict->value == 0x0A )
        {
            pict->line -= 1;
            pict->position = 0;
        }
        else
        {
            pict->position -= 1;
        }
    }
    else if( pict->flag == 1 )
    {
        // 溢出。
    }
    else if( pict->flag == 2 )
    {
        //
        pict->flag = 3;
    }
    else if( pict->flag == 3 )
    {
        // 溢出。
    }
    else
    {
        // do nothing.
    }
}


void  in_clear_until_lined( tetra  ptetra )
{
    tetra  ch;
    
    do {
        ch = in_next_nospace( ptetra );
    } while( ch != 0x0A );

    return;
}


tetra  in_get_position( tetra  ptetra )
{
    input_context * pict;
    pict = (input_context *)ptetra;

    return  ( (pict->line << 16) + pict->position );
}


/*
********************************************************************************
* 功能:
*    使用上面定义的这个 input_context 上下文结构，读取文件中的下一个字符。
*
* 输入:
*    input_context * , 所使用的上下文结构。
*
* 输出:
*    input_context * , 此结构中的 value 成员指出读取的字符值。
*    应该定义两个特殊字符，一个是文件结束 0xFFFFFFFF，一个是错误的字符值( 表明该字符不属于指定的
*    编码之中 )
*
********************************************************************************
*/

void  in_fini_context( tetra  ptetra )
{
    input_context * pict;

    pict = (input_context *)ptetra;
    
    fclose( pict->fp );                             // 关闭文件。
    free( pict );                                   // 释放数据结构。
    
}




/*
********************************************************************************
* 功能:
*    输出文件名和当前行号。
*
* 输入:
*    input_context * , 所使用的上下文结构。
*
* 输出:
*    无
*
********************************************************************************
*/

void  in_error_out( tetra  ptetra )
{
    input_context *  pict;

    pict = (input_context *)pict;
    printf("fname:%d", pict->line );
}




